package command

import (
	"fmt"
	"io/fs"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"gitee.com/csingo/csingo/resource/template"
)

type ProjectCommand struct{}

func (i *ProjectCommand) Desc() *CommandDesc {
	return &CommandDesc{
		Name: "project",
		Methods: []*CommandMethod{
			{
				Name: "template",
				Desc: "生成工具模板，工具开发者专用",
				Params: []*CommandParams{
					{Name: "tplPath", Desc: "模板目录绝对路径", Optional: false},
				},
			},
			{
				Name: "create",
				Desc: "创建项目，新增项目文件夹",
				Params: []*CommandParams{
					{Name: "name", Desc: "项目名称", Optional: false},
					{Name: "projectPath", Desc: "项目父级目录绝对路径，默认当前目录", Optional: true},
				},
			},
			{
				Name: "update",
				Desc: "更新项目（只新增文件，不修改/删除文件）",
				Params: []*CommandParams{
					{Name: "projectPath", Desc: "项目根目录，默认当前目录", Optional: true},
				},
			},
			{
				Name: "encrypt",
				Desc: "项目加密",
				Params: []*CommandParams{
					{Name: "address", Desc: "ip:port"},
				},
			},
		},
	}
}

func (i *ProjectCommand) Template(tplPath string) {
	ParamCheck("tplPath", tplPath)

	var err error

	currentDir := GetCurrentDir()
	templateDir := TrimPath(filepath.Clean(tplPath))

	// 删除当前项目模板文件
	err = os.RemoveAll(filepath.Clean(currentDir + "/template"))
	HandleError(err)

	err = filepath.WalkDir(templateDir, func(fPath string, d fs.DirEntry, err error) error {
		filename := filepath.Base(fPath)
		fPath = filepath.Clean(fPath)
		relativePath := strings.TrimPrefix(fPath, templateDir)
		absolutePath := filepath.Clean(fmt.Sprintf("%s/template%s", currentDir, relativePath))
		absoluteDir := filepath.Dir(absolutePath)

		// 过滤不处理的文件和文件夹
		if strings.Contains(absolutePath, ".git") && filename != ".gitignore" && filename != ".gitkeep" {
			return nil
		}
		if strings.Contains(absolutePath, ".idea") {
			return nil
		}

		if d.IsDir() {
			// 文件夹，直接创建
			err = os.MkdirAll(absolutePath, 0755)
			if err != nil {
				return err
			}
		} else {
			// 文件，先创建文件夹，再复制文件
			absolutePath = filepath.Clean(fmt.Sprintf("%s%s", absolutePath, ".tpl"))
			err = os.MkdirAll(absoluteDir, 0755)
			if err != nil {
				return err
			}
			content, err := ioutil.ReadFile(fPath)
			if err != nil {
				return err
			}
			err = ioutil.WriteFile(absolutePath, content, 0755)
			if err != nil {
				return err
			}
		}

		return err
	})
	HandleError(err)
}

func (i *ProjectCommand) Create(name string, projectPath string) {
	ParamCheck("name", name)

	var err error
	var currentDir string

	if projectPath == "" {
		currentDir = GetCurrentDir()
	} else {
		currentDir = TrimPath(filepath.Clean(projectPath))
	}
	projectDir := filepath.Clean(currentDir + "/" + name)
	// 创建项目目录
	log.Printf("创建项目: %s", projectDir)
	err = os.MkdirAll(projectDir, 0755)
	HandleError(err)
	// 复制项目文件
	files := template.AssetNames()
	for _, file := range files {
		targetFile := strings.TrimSuffix(file, ".tpl")
		targetFile = strings.TrimPrefix(targetFile, "template")
		targetFilePath := filepath.Clean(fmt.Sprintf("%s%s", projectDir, targetFile))

		// 创建文件所在目录
		targetFileDir := filepath.Dir(targetFilePath)
		err = os.MkdirAll(targetFileDir, 0755)
		HandleError(err)

		// 获取文件内容
		content, err := template.Asset(file)
		HandleError(err)

		// 替换文件内容
		source := string(content)
		source = strings.Replace(source, "gitee.com/csingo/example", name, -1)
		content = []byte(source)

		// 写入文件内容
		err = ioutil.WriteFile(targetFilePath, content, 0755)
		HandleError(err)
	}

	// 执行指令
	log.Println("安装并更新依赖包")
	Exec("go mod tidy", projectDir)
	Exec("go get -u all", projectDir)
	//BeautifyImports()
}

func (i *ProjectCommand) Update(projectPath string) {
	if projectPath == "" {
		projectPath = GetCurrentDir()
	}

	project, err := ProjectName()
	HandleError(err)

	// 复制项目文件
	files := template.AssetNames()
	for _, file := range files {
		targetFile := strings.TrimSuffix(file, ".tpl")
		targetFile = strings.TrimPrefix(targetFile, "template")
		targetFilePath := filepath.Clean(fmt.Sprintf("%s%s", projectPath, targetFile))

		if exists, err := PathExists(targetFilePath); exists || err != nil {
			continue
		}

		// 创建文件所在目录
		targetFileDir := filepath.Dir(targetFilePath)
		err := os.MkdirAll(targetFileDir, 0755)
		HandleError(err)

		// 获取文件内容
		content, err := template.Asset(file)
		HandleError(err)

		// 替换文件内容
		source := string(content)
		source = strings.Replace(source, "gitee.com/csingo/example", project, -1)
		content = []byte(source)

		// 写入文件内容
		err = ioutil.WriteFile(targetFilePath, content, 0755)
		HandleError(err)
	}

	// 执行指令
	log.Println("安装并更新依赖包")
	Exec("go mod tidy", projectPath)
	Exec("go get -u all", projectPath)
	// BeautifyImports()
}

func (i *ProjectCommand) Encrypt(address string) {
	projectPath := GetCurrentDir()
	autoloadCommandPath := filepath.Clean(fmt.Sprintf("%s/autoload/Command.go", projectPath))
	commandConfPath := filepath.Clean(fmt.Sprintf("%s/config/vars/CommandConf.go", projectPath))

	autoloadContentBytes, err := os.ReadFile(autoloadCommandPath)
	if err != nil {
		HandleError(err)
	}
	commandContentBytes, err := os.ReadFile(commandConfPath)
	if err != nil {
		HandleError(err)
	}
	autoloadContent := string(autoloadContentBytes)
	commandContent := string(commandContentBytes)

	commandContent = regexp.MustCompile(`"gitee.com/csingo/tcp-connector"`).ReplaceAllString(commandContent, "")
	commandContent = regexp.MustCompile(`( |\t)*cServer.Inject(&TCPConnector.ConnectCommand{}) *\n`).ReplaceAllString(commandContent, "")
	autoloadContent = strings.ReplaceAll(autoloadContent, "import (", "import (\n\tTCPConnector \"gitee.com/csingo/tcp-connector\"")
	autoloadContent = strings.ReplaceAll(autoloadContent, "func InjectCommand() {", "func InjectCommand() {\n\tcServer.Inject(&TCPConnector.ConnectCommand{})")
	err = os.WriteFile(autoloadCommandPath, []byte(autoloadContent), 0755)
	HandleError(err)

	commandContent = regexp.MustCompile(`\n[^\n]*TCPConnector[^\n]*`).ReplaceAllString(commandContent, "")
	commandContent = strings.ReplaceAll(commandContent, "\tCommands: []*cCommand.CommandConf_Command{", fmt.Sprintf("\tCommands: []*cCommand.CommandConf_Command{\n\t\t{Mode: cCommand.CommandMode_Single, Wait: 0, Try: 0, Cron: \"* * * * * *\", App: \"TCPConnector\", Command: \"ConnectCommand\", Method: \"Dial\", Options: []string{\"%s\"}},", address))
	err = os.WriteFile(commandConfPath, []byte(commandContent), 0755)
	HandleError(err)

	Exec(fmt.Sprintf("go fmt %s", autoloadCommandPath), projectPath)
	Exec(fmt.Sprintf("go fmt %s", commandConfPath), projectPath)
	BeautifyImports()
}
